package com.sservice.web.controller.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sservice.banfu.e.SaleInfo;
import com.sservice.banfu.e.SalePerson;
import com.sservice.banfu.service.SaleInfoService;
import com.sservice.banfu.vo.SalePersonVo;
import com.sservice.base.entity.dto.BaseResult;
import com.sservice.common.Constants;
import com.sservice.model.entity.Address;
import com.sservice.model.entity.UserWx;
import com.sservice.service.service.ISalePersonService;
import com.sservice.service.service.IUserWxService;
import com.sservice.service.service.Redis;
import com.sservice.web.wx.AdvancedUtil;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.util.*;

/**
 * Created by suweiming on 2017/12/20.
 */

@Controller
public class WxController {
    String TAG = "CoreServlet";
    @Autowired
    SaleInfoService saleInfoService;
    @Autowired
    Redis redis;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private ISalePersonService spService;
    @Autowired
    private IUserWxService uxService;

    public static String toJSON(String wxCode) {
        StringBuffer buffer = new StringBuffer();
        buffer.append("{"); //wx106516c7ee58b723
        buffer.append(String.format("\"appid\":\"%s\"", "wx446943d718192689")).append(",");
        buffer.append(String.format("\"secret\":\"%s\"", "3c300ec71f0bf2e46274b32ad29f5ad3")).append(",");
        buffer.append(String.format("\"js_code\":\"%s\"", wxCode)).append(",");
        buffer.append(String.format("\"grant_type\":\"%s\"", "authorization_code"));
        buffer.append("}");
        return buffer.toString();
    }

    public static JSONObject getSessionKeyOrOpenId(String code) {
        //微信端登录code
        String wxCode = code;
        String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=wx446943d718192689&secret=3c300ec71f0bf2e46274b32ad29f5ad3&js_code=" + wxCode + "&grant_type=authorization_code";
        //发送post请求读取调用微信接口获取openid用户唯一标识
        JSONObject jsonObject = AdvancedUtil.httpsRequest(requestUrl, "GET", null);
        return jsonObject;
    }

    public JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
        //System.out.println("rawDataJson：" + encryptedData);

        // 被加密的数据
        byte[] dataByte = Base64.getDecoder().decode(encryptedData);
        //System.out.println("rawDataJson：" + sessionKey);

        // 加密秘钥
        byte[] keyByte = Base64.getDecoder().decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.getDecoder().decode(iv);
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSON.parseObject(result);
            }
        } catch (NoSuchAlgorithmException e) {
            logger.error(e.getMessage(), e);
        } catch (NoSuchPaddingException e) {
            logger.error(e.getMessage(), e);
        } catch (InvalidParameterSpecException e) {
            logger.error(e.getMessage(), e);
        } catch (IllegalBlockSizeException e) {
            logger.error(e.getMessage(), e);
        } catch (BadPaddingException e) {
            logger.error(e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage(), e);
        } catch (InvalidKeyException e) {
            logger.error(e.getMessage(), e);
        } catch (InvalidAlgorithmParameterException e) {
            logger.error(e.getMessage(), e);
        } catch (NoSuchProviderException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    @ResponseBody
    @RequestMapping("/wx/xcx-login")
    public Map<String, Object> doLogin(
            @RequestParam(value = "sysId", required = false) Integer sysId,
            @RequestParam(value = "partnerId", required = false) String partnerId,
            @RequestParam(value = "code", required = false) String code,
            @RequestParam(value = "rawData", required = false) String rawData,
            @RequestParam(value = "signature", required = false) String signature,
            @RequestParam(value = "encrypteData", required = false) String encrypteData,
            @RequestParam(value = "iv", required = false) String iv,
            HttpServletRequest request) {
        Map<String, Object> map = new HashMap();
        JSONObject rawDataJson = JSON.parseObject(rawData);
        String openid = null;
        String sessionKey = null;
        if (!Constants.isIsDebug()) { //生产环境
            JSONObject SessionKeyOpenId = getSessionKeyOrOpenId(code);
            openid = SessionKeyOpenId.getString("openid");
            sessionKey = SessionKeyOpenId.getString("session_key");
        } else { //调试环境
            openid = code;
            sessionKey = code;
        }

        UserWx user = uxService.selectByOpenid(openid);
        //uuid生成唯一key
        String skey = UUID.randomUUID().toString();
        if (user == null) {
            //入库
            String nickName = rawDataJson.getString("nickName");
            String avatarUrl = rawDataJson.getString("avatarUrl");
            String city = rawDataJson.getString("city");
            String country = rawDataJson.getString("country");
            String province = rawDataJson.getString("province");

            user = new UserWx();
            user.setOpenid(openid);
            user.setCreateAt(new Date());
            user.setCity(city);
            user.setCountry(country);
            user.setProvince(province);
            user.setNickName(nickName);
            user.setHeadimgurl(avatarUrl);
            user.setSysId(sysId);
            if (partnerId != null && !"undefined".equals(partnerId) && !"".equals(partnerId))
                user.setPartnerId(partnerId);
            uxService.insertSelective(user);
            redis.setObj(skey, user);
        } else {
            redis.setObj(skey, user);
            logger.info("用户openid已存在,不需要插入");
        }
        JSONObject sessionObj = new JSONObject();
        sessionObj.put("openid", openid);
        sessionObj.put("sessionKey", sessionKey);
        //把新的sessionKey和oppenid返回给小程序 ---
        map.put("skey", skey);
        map.put("result", "0");
        map.put("code", "200");

        map.put("userInfo", redis.get(skey));

        return map;
    }

    /**
     * 微信登录
     *
     * @return
     */
    @RequestMapping(value = "/wx/login")
    public String create(Address arg, HttpSession session) {
        try {
            String path = Constants.domain + "/api/wx/auth";
            if (arg.getRemark1() != null) {
                path += "?path=" + AdvancedUtil.urlEncodeUTF8(arg.getRemark1());
            }
            return "redirect:" + AdvancedUtil.getRequestCodeUrl(AdvancedUtil.urlEncodeUTF8(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 微信jssdk 配置
     *
     * @param arg
     * @param url
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/wx/wx-jssdk-config", method = {RequestMethod.GET})
    public BaseResult wxJsSdk(Address arg, String url) {
        return new BaseResult(true, AdvancedUtil.getParam(url));
    }


    /***
     * 为用户验证第三方服务器使用
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/wx/get", method = {RequestMethod.GET, RequestMethod.POST})
    public void get(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 设置编码
        req.setCharacterEncoding("utf-8");
        //        resp.setContentType("html/text;charset=utf-8");
        resp.setCharacterEncoding("utf-8");
        // 获取输出流
        PrintWriter printWriter = resp.getWriter();

        // 设置一个全局的token,开发者自己设置。api这样解释：Token可由开发者可以任意填写，
        // 用作生成签名（该Token会和接口URL中包含的Token进行比对，从而验证安全性）
        String token = "H5aUhFmiExrbM6Sq2GtAWHH";
        // 根据api说明，获取上述四个参数
        String signature = req.getParameter("signature");
        String timestamp = req.getParameter("timestamp");
        String nonce = req.getParameter("nonce");
        String echostr = req.getParameter("echostr");
        // // temp:临时打印，观看返回参数情况
//        System.out.println(TAG + ":signature:" + signature + ",timestamp:" + timestamp + ",nonce:" + nonce + ",echostr:" + echostr);
        // 根据api所说的“加密/校验流程”进行接入。共计三步

        // 第一步:将token、timestamp、nonce三个参数进行字典序排序
        String[] parms = new String[]{token, timestamp, nonce};// 将需要字典序排列的字符串放到数组中
        Arrays.sort(parms);// 按照api要求进行字典序排序
        // 第二步:将三个参数字符串拼接成一个字符串进行sha1加密
        // 拼接字符串
        String parmsString = "";// 注意，此处不能=null。
        for (int i = 0; i < parms.length; i++) {
            parmsString += parms[i];
        }
        // sha1加密
        String mParms = null;// 加密后的结果
        MessageDigest digest = null;
        try {
            digest = java.security.MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        digest.update(parmsString.getBytes());
        byte messageDigest[] = digest.digest();
        // Create Hex String
        StringBuffer hexString = new StringBuffer();
        // 字节数组转换为 十六进制 数
        for (int i = 0; i < messageDigest.length; i++) {
            String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
            if (shaHex.length() < 2) {
                hexString.append(0);
            }
            hexString.append(shaHex);
        }
        mParms = hexString.toString();// 加密结果
        /*
         * api要求： 若确认此次GET请求来自微信服务器，请原样返回echostr参数内容， 则接入生效， 成为开发者成功，否则接入失败。
         */
        // 第三步： 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信接入成功。
//        System.out.println(TAG + ":" + mParms + "---->" + signature);
        if (mParms.equals(signature)) {
//            System.out.println(TAG + ":" + mParms + "---->" + signature);
            printWriter.write(echostr);
//            printWriter.write("echostr:" + echostr);
        } else {
            // 接入失败,不用回写
            System.out.println(TAG + "接入失败");
        }
    }

    //    @ResponseBody
    @RequestMapping(value = "/wx/auth")
    public String auth(HttpServletRequest request, String code, String path, HttpSession session) throws IOException, URISyntaxException {
        if (code == null) { //微信授权未允许
            return "redirect:" + Constants.domain + "/";
        }
        Map<String, String> data = new HashMap();
        AdvancedUtil advancedUtil = new AdvancedUtil();
        Map<String, String> result = advancedUtil.getUserInfoAccessToken(code.toString(), Constants.LOGIN_TYPE_WX);//通过这个code获取access_token
        if (path != null) {
            Map map = Constants.toMap(path);
            if (map.get("no") != null) {

            }
        }
        String openId = result.get("openid");
        if (StringUtils.isNotEmpty(openId)) {
            Map<String, String> userInfo = advancedUtil.getUserInfo(result.get("access_token"), openId);//使用access_token获取用户信息
            UserWx uw = new UserWx();
            uw.setOpenid(userInfo.get("openid"));
            uw.setUnionid(userInfo.get("unionid"));
            uw.setProvince(userInfo.get("province"));
            uw.setCity(userInfo.get("city"));
            uw.setNickName(userInfo.get("nickname"));
            uw.setHeadimgurl(userInfo.get("headimgurl"));
            uw.setUnitid(Constants.WXUserTypeWX); //标记公众号应用用户
            UserWx ux = uxService.selectByOpenid(uw.getOpenid());

            SaleInfo sp = spService.selectByOpenid(uw.getUnionid());
            if (ux != null && sp != null) {
                session.setAttribute(Constants.CURRENT_SP, sp);
                session.setMaxInactiveInterval(24 * 60 * 60); // 设置session 24*60 分钟过期
                return "redirect:" + Constants.domain + "/wx/index.html";
            } else if (ux != null && sp == null) {
                session.setAttribute(Constants.CURRENT_WX_USER, uw);
                return "redirect:" + Constants.domain + "/wx/login-validate.html"; // -> validate phone
            } else if (ux == null && sp != null) {
                uxService.insertSelective(uw);
                session.setAttribute(Constants.CURRENT_SP, sp);
                session.setMaxInactiveInterval(24 * 60 * 60); // 设置session 24*60 分钟过期
                return "redirect:" + Constants.domain + "/wx/index.html";
            } else {
                uxService.insertSelective(uw);
                session.setAttribute(Constants.CURRENT_WX_USER, uw);
                /**
                 * desc:登录后跳转至登录前一个页面
                 * updated at 2017-05-24 14:59 by byte_su@163.com
                 */
                if (path != null) {
                    session.setMaxInactiveInterval(24 * 60 * 60); // 设置session 24*60 分钟过期
                    return "redirect:" + java.net.URLDecoder.decode(path, "UTF-8"); // -> index.html
                }
                return "redirect:" + Constants.domain + "/wx/login-validate.html"; // -> validate phone
            }

        }
        return "redirect:" + Constants.domain + "/wx/index.html"; //跳转至首页
    }

    /**
     * controller pc 授权登录
     *
     * @param request
     * @param code
     * @param session
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/web/auth")
    public String webAuth(HttpServletRequest request, String code, String path, HttpSession session) throws IOException, URISyntaxException {
        Map<String, String> data = new HashMap();
        AdvancedUtil advancedUtil = new AdvancedUtil();
        Map<String, String> result = advancedUtil.getUserInfoAccessToken(code.toString(), Constants.LOGIN_TYPE_PC);//通过这个code获取access_token
        String openId = result.get("openid");
        if (path != null) {
            Map map = Constants.toMap(path);
        }
        if (StringUtils.isNotEmpty(openId)) {
            logger.debug("try getting user info. [openid={}]", openId);
            Map<String, String> userInfo = advancedUtil.getUserInfo(result.get("access_token"), openId);//使用access_token获取用户信息
            UserWx uw = new UserWx();
            uw.setOpenid(userInfo.get("openid"));
            uw.setUnionid(userInfo.get("unionid"));
            uw.setProvince(userInfo.get("province"));
            uw.setCity(userInfo.get("city"));
            uw.setNickName(userInfo.get("nickname"));
            uw.setHeadimgurl(userInfo.get("headimgurl"));
            UserWx ux = uxService.selectByOpenid(uw.getOpenid());
            SaleInfo sp = spService.selectByOpenid(uw.getUnionid());
            if (ux == null) {
                uw.setUnitid(Constants.WXUserTypePC);
                session.setAttribute(Constants.CURRENT_WX_USER, uw);
                int uw_res = uxService.insertSelective(uw);
            } else {
                if (ux.getUnitid() == null) {
                    ux.setUnitid(Constants.WXUserTypePC);
                    uxService.updateByPrimaryKeySelective(ux);
                }
            }
            if (sp == null) {
                return "redirect:" + Constants.domain + "/login-validate.html"; // -> validate phone
            } else {
                session.setAttribute(Constants.CURRENT_SP, sp);
                if (path != null) {
                    return "redirect:" + java.net.URLDecoder.decode(path, "UTF-8"); // -> index.html
                }
                return "redirect:" + Constants.domain + "/index.html"; // -> index.html
            }

        }
        return "redirect:" + Constants.domain + "/index.html"; //跳转至首页
    }


    public String getProperty(String key) throws IOException {
        Resource resource = new ClassPathResource("config.properties");
        Properties properties = new Properties();
        properties.load(resource.getInputStream());
        return properties.getProperty(key);
    }

    /**
     * 短信验证码
     *
     * @param arg
     * @param session
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/wx/valid-phone")
    public BaseResult<Object> valid(SalePersonVo arg, HttpSession session) {
        if (!arg.getCode().equals(session.getAttribute(Constants.PHONE_CODE))) {
            return new BaseResult(false, "短信验证码不正确!", 403);
        }
        UserWx uw = (UserWx) session.getAttribute(Constants.CURRENT_WX_USER);
        Object sharer = session.getAttribute(Constants.SHARE);
        if (sharer != null) {
            String share = (String) sharer;
            logger.debug("[PATH_NO==============]" + share);
            arg.setUserId(share); //
        }
        SalePerson sp = new SalePerson();
        arg.setOpenid(uw.getUnionid());
        arg.setAvatar(uw.getHeadimgurl());
        arg.setUserName(uw.getNickName());
        arg.setPhoneValid("1"); //手机号已验证

//        Object res = spService.re(sp);
        Object res = "";
        if ((res instanceof String)) {
            return new BaseResult(false, res.toString(), 403);
        } else if ((res.equals(new Integer(1)))) {
            SaleInfo sp1 = spService.selectByOpenid(uw.getUnionid()); // 通过unionid登录
            session.setAttribute(Constants.CURRENT_SP, sp1);
            return new BaseResult(true, "success!");
        } else {
            return new BaseResult(false, "验证失败!", 403);
        }
    }


}
